/**
 * @p.md
 * 
 * MessageInvoker 模块，负责在 Actor 上调用消息处理
 */
import { Actor } from './actor';
import { Context } from './context';
import { PID } from './pid';

/**
 * 消息调用器接口，定义了消息处理的执行方式
 */
export interface MessageInvoker {
  /**
   * 调用用户消息处理
   * @param actor 目标 Actor
   * @param context 上下文
   * @param message 消息
   */
  invokeUserMessage(actor: Actor, context: Context, message: any): void;
  
  /**
   * 调用系统消息处理
   * @param actor 目标 Actor
   * @param context 上下文
   * @param message 系统消息
   */
  invokeSystemMessage(actor: Actor, context: Context, message: any): void;
  
  /**
   * 处理错误情况
   * @param actor 目标 Actor
   * @param reason 错误原因
   */
  escalateFailure(actor: Actor, reason: Error): void;
}

/**
 * 默认消息调用器，实现基本的消息调用逻辑
 */
export class DefaultMessageInvoker implements MessageInvoker {
  /**
   * 调用用户消息处理逻辑
   * @param actor 目标 Actor
   * @param context 上下文
   * @param message 消息
   */
  invokeUserMessage(actor: Actor, context: Context, message: any): void {
    try {
      // 调用 Actor 的接收方法处理消息
      actor.receive(context);
    } catch (error) {
      // 如果处理过程中出现错误，升级到错误处理
      this.escalateFailure(actor, error as Error);
    }
  }
  
  /**
   * 调用系统消息处理逻辑
   * @param actor 目标 Actor
   * @param context 上下文
   * @param message 系统消息
   */
  invokeSystemMessage(actor: Actor, context: Context, message: any): void {
    try {
      // 系统消息通常由特定的处理逻辑，如果 Actor 实现了系统消息处理接口则调用
      if ('receiveSystemMessage' in actor) {
        (actor as any).receiveSystemMessage(context);
      }
    } catch (error) {
      // 如果处理过程中出现错误，升级到错误处理
      this.escalateFailure(actor, error as Error);
    }
  }
  
  /**
   * 将错误升级到监督系统处理
   * @param actor 目标 Actor
   * @param reason 错误原因
   */
  escalateFailure(actor: Actor, reason: Error): void {
    // 获取关联的 Context 和 PID
    // 注意：在实际实现中，这里应该通过 ProcessRegistry 或其他机制获取 Actor 的父级和监督者
    const pid = (actor as any).self as PID;
    
    // 将错误发送给监督者处理
    if (pid) {
      // 获取父级 PID（通常应该通过 ActorSystem 或 ProcessRegistry 获取）
      // 由于 PID 类型没有直接的 parent 属性，这里修改为通过其他方式获取
      console.error(`Actor ${pid.id} failed with error: ${reason.message}`);
      // 在完整实现中，应该调用 actorSystem.root.send(supervisorPid, new Failure(pid, reason));
    } else {
      // 如果没有监督者，记录错误
      console.error(`Unhandled actor failure: ${reason.message}`, reason);
    }
  }
}

/**
 * 中间件增强的消息调用器，支持消息处理前后的拦截
 */
export class MiddlewareInvoker implements MessageInvoker {
  private readonly _next: MessageInvoker;
  private readonly _middleware: Array<(next: MessageInvoker) => MessageInvoker>;
  
  /**
   * 构造带有中间件的消息调用器
   * @param next 下一个调用器
   * @param middleware 中间件列表
   */
  constructor(next: MessageInvoker, middleware: Array<(next: MessageInvoker) => MessageInvoker>) {
    this._next = next;
    this._middleware = middleware;
  }
  
  /**
   * 通过中间件调用用户消息
   * @param actor 目标 Actor
   * @param context 上下文
   * @param message 消息
   */
  invokeUserMessage(actor: Actor, context: Context, message: any): void {
    // 应用中间件链，从最外层开始逐层调用
    let invoker: MessageInvoker = this._next;
    
    for (let i = this._middleware.length - 1; i >= 0; i--) {
      invoker = this._middleware[i](invoker);
    }
    
    // 最终调用经过所有中间件处理的消息
    invoker.invokeUserMessage(actor, context, message);
  }
  
  /**
   * 通过中间件调用系统消息
   * @param actor 目标 Actor
   * @param context 上下文
   * @param message 系统消息
   */
  invokeSystemMessage(actor: Actor, context: Context, message: any): void {
    // 系统消息通常不经过中间件处理，直接传递给下一个调用器
    this._next.invokeSystemMessage(actor, context, message);
  }
  
  /**
   * 错误处理升级
   * @param actor 目标 Actor
   * @param reason 错误原因
   */
  escalateFailure(actor: Actor, reason: Error): void {
    this._next.escalateFailure(actor, reason);
  }
}

/**
 * 消息调用器工厂，提供创建不同类型调用器的方法
 */
export const MessageInvokers = {
  /**
   * 创建默认消息调用器
   * @returns 默认消息调用器实例
   */
  defaultInvoker(): MessageInvoker {
    return new DefaultMessageInvoker();
  },
  
  /**
   * 创建带有中间件的消息调用器
   * @param middleware 中间件列表
   * @returns 带有中间件的消息调用器
   */
  withMiddleware(middleware: Array<(next: MessageInvoker) => MessageInvoker>): MessageInvoker {
    return new MiddlewareInvoker(new DefaultMessageInvoker(), middleware);
  }
}; 